import uuid
from datetime import datetime, timezone
from typing import List, Optional, Dict, Any
from elasticsearch import Elasticsearch
from app.config.settings import settings
from app.models.notification import (
    NotificationCreate, 
    NotificationUpdate, 
    NotificationInDB,
    NotificationResponse,
    NotificationListResponse,
    UnreadCountResponse
)
from app.utils.elasticsearch import ESClient
import logging

logger = logging.getLogger(__name__)

class NotificationService:
    def __init__(self):
        self.es: Elasticsearch = ESClient.get_client()
        self.notification_index = f"{settings.ES_INDEX_PREFIX}_notifications"
        self.user_notification_index = f"{settings.ES_INDEX_PREFIX}_user_notifications"
        
        # 确保索引存在
        self._ensure_indices_exist()
    
    def _ensure_indices_exist(self):
        """确保Elasticsearch索引存在"""
        try:
            # 通知索引
            if not self.es.indices.exists(index=self.notification_index):
                self.es.indices.create(
                    index=self.notification_index,
                    body={
                        "mappings": {
                            "properties": {
                                "id": {"type": "keyword"},
                                "title": {"type": "text"},
                                "content": {"type": "text"},
                                "type": {"type": "keyword"},
                                "priority": {"type": "keyword"},
                                "target_users": {"type": "keyword"},
                                "created_by": {"type": "keyword"},
                                "created_at": {"type": "date"},
                                "expires_at": {"type": "date"},
                                "is_active": {"type": "boolean"},
                                "updated_at": {"type": "date"}
                            }
                        }
                    }
                )
                logger.info(f"创建索引: {self.notification_index}")
            
            # 用户通知状态索引
            if not self.es.indices.exists(index=self.user_notification_index):
                self.es.indices.create(
                    index=self.user_notification_index,
                    body={
                        "mappings": {
                            "properties": {
                                "user_id": {"type": "keyword"},
                                "notification_id": {"type": "keyword"},
                                "is_read": {"type": "boolean"},
                                "read_at": {"type": "date"},
                                "created_at": {"type": "date"}
                            }
                        }
                    }
                )
                logger.info(f"创建索引: {self.user_notification_index}")
                
        except Exception as e:
            logger.error(f"创建索引失败: {e}")
            raise
    
    def create_notification(self, notification: NotificationCreate, created_by: str) -> NotificationInDB:
        """创建新通知"""
        try:
            notification_id = str(uuid.uuid4())
            now = datetime.now(timezone.utc)
            
            notification_data = {
                "id": notification_id,
                "title": notification.title,
                "content": notification.content,
                "type": notification.type.value,
                "priority": notification.priority.value,
                "target_users": notification.target_users or [],  # 空列表表示所有用户
                "created_by": created_by,
                "created_at": now.isoformat(),
                "updated_at": now.isoformat(),
                "expires_at": notification.expires_at.isoformat() if notification.expires_at else None,
                "is_active": notification.is_active
            }
            
            # 保存通知
            self.es.index(
                index=self.notification_index,
                id=notification_id,
                body=notification_data
            )
            
            # 不在这里创建用户通知记录，而是在查询时动态处理
            logger.info(f"创建通知成功: {notification_id}")
            return NotificationInDB(**notification_data)
            
        except Exception as e:
            logger.error(f"创建通知失败: {e}")
            raise
    

    
    def get_notification(self, notification_id: str) -> Optional[NotificationInDB]:
        """根据ID获取通知"""
        try:
            result = self.es.get(
                index=self.notification_index,
                id=notification_id
            )
            
            if result["found"]:
                return NotificationInDB(**result["_source"])
            return None
            
        except Exception as e:
            logger.error(f"获取通知失败: {e}")
            return None
    
    def update_notification(self, notification_id: str, notification: NotificationUpdate) -> Optional[NotificationInDB]:
        """更新通知"""
        try:
            # 检查通知是否存在
            existing = self.get_notification(notification_id)
            if not existing:
                return None
            
            # 构建更新数据
            update_data = {}
            if notification.title is not None:
                update_data["title"] = notification.title
            if notification.content is not None:
                update_data["content"] = notification.content
            if notification.type is not None:
                update_data["type"] = notification.type.value
            if notification.priority is not None:
                update_data["priority"] = notification.priority.value
            if notification.target_users is not None:
                update_data["target_users"] = notification.target_users
            if notification.expires_at is not None:
                update_data["expires_at"] = notification.expires_at.isoformat()
            if notification.is_active is not None:
                update_data["is_active"] = notification.is_active
            
            update_data["updated_at"] = datetime.now(timezone.utc).isoformat()
            
            # 更新通知
            self.es.update(
                index=self.notification_index,
                id=notification_id,
                body={"doc": update_data}
            )
            
            # 如果目标用户发生变化，不需要特殊处理，查询时会动态处理
            # 删除旧的用户通知记录（可选，为了清理数据）
            if notification.target_users is not None and notification.target_users != existing.target_users:
                self._cleanup_old_user_notification_records(notification_id, existing.target_users)
            
            logger.info(f"更新通知成功: {notification_id}")
            
            # 返回更新后的通知
            return self.get_notification(notification_id)
            
        except Exception as e:
            logger.error(f"更新通知失败: {e}")
            return None
    
    def _cleanup_old_user_notification_records(self, notification_id: str, old_users: List[str]):
        """清理旧的用户通知记录（可选，用于数据清理）"""
        try:
            if old_users:
                for user_id in old_users:
                    self.es.delete_by_query(
                        index=self.user_notification_index,
                        body={
                            "query": {
                                "bool": {
                                    "must": [
                                        {"term": {"user_id": user_id}},
                                        {"term": {"notification_id": notification_id}}
                                    ]
                                }
                            }
                        }
                    )
                logger.info(f"清理了通知 {notification_id} 的旧用户记录")
        except Exception as e:
            logger.error(f"清理用户通知记录失败: {e}")
    
    def delete_notification(self, notification_id: str) -> bool:
        """删除通知"""
        try:
            # 删除通知
            self.es.delete(
                index=self.notification_index,
                id=notification_id
            )
            
            # 删除相关的用户通知记录
            self.es.delete_by_query(
                index=self.user_notification_index,
                body={
                    "query": {
                        "term": {"notification_id": notification_id}
                    }
                }
            )
            
            logger.info(f"删除通知成功: {notification_id}")
            return True
            
        except Exception as e:
            logger.error(f"删除通知失败: {e}")
            return False
    
    def get_all_notifications(self, page: int = 1, size: int = 20) -> NotificationListResponse:
        """获取所有通知（分页）"""
        try:
            from_index = (page - 1) * size
            
            # 查询通知
            query_body = {
                "query": {"match_all": {}},
                "sort": [{"created_at": {"order": "desc"}}],
                "from": from_index,
                "size": size
            }
            
            result = self.es.search(
                index=self.notification_index,
                body=query_body
            )
            
            notifications = []
            for hit in result["hits"]["hits"]:
                notifications.append(NotificationResponse(**hit["_source"]))
            
            total = result["hits"]["total"]["value"]
            
            return NotificationListResponse(
                notifications=notifications,
                total=total,
                page=page,
                size=size
            )
            
        except Exception as e:
            logger.error(f"获取通知列表失败: {e}")
            return NotificationListResponse(notifications=[], total=0, page=page, size=size)
    
    def get_user_notifications(self, user_id: str, page: int = 1, size: int = 20) -> NotificationListResponse:
        """获取用户的通知列表"""
        try:
            # 1. 获取所有活跃通知
            all_notifications = self._get_all_active_notifications()
            
            # 2. 过滤用户可见的通知
            user_notifications = []
            for notification in all_notifications:
                if self._is_notification_visible_to_user(notification, user_id):
                    # 3. 获取或创建用户通知状态记录
                    user_notification_status = self._get_or_create_user_notification_status(
                        user_id, notification.id
                    )
                    
                    # 4. 构建响应
                    notification_response = NotificationResponse(
                        id=notification.id,
                        title=notification.title,
                        content=notification.content,
                        type=notification.type,
                        priority=notification.priority,
                        target_users=notification.target_users,
                        created_by=notification.created_by,
                        created_at=notification.created_at,
                        expires_at=notification.expires_at,
                        is_active=notification.is_active,
                        is_read=user_notification_status["is_read"],
                        read_at=user_notification_status.get("read_at")
                    )
                    user_notifications.append(notification_response)
            
            # 5. 分页处理
            total = len(user_notifications)
            start_idx = (page - 1) * size
            end_idx = start_idx + size
            paginated_notifications = user_notifications[start_idx:end_idx]
            
            return NotificationListResponse(
                notifications=paginated_notifications,
                total=total,
                page=page,
                size=size
            )
            
        except Exception as e:
            logger.error(f"获取用户通知失败: {e}")
            return NotificationListResponse(notifications=[], total=0, page=page, size=size)
    
    def get_unread_count(self, user_id: str) -> UnreadCountResponse:
        """获取用户未读通知数量"""
        try:
            # 获取所有活跃通知
            all_notifications = self._get_all_active_notifications()
            
            unread_count = 0
            for notification in all_notifications:
                if self._is_notification_visible_to_user(notification, user_id):
                    # 获取或创建用户通知状态记录
                    user_notification_status = self._get_or_create_user_notification_status(
                        user_id, notification.id
                    )
                    
                    # 如果未读，计数加1
                    if not user_notification_status["is_read"]:
                        unread_count += 1
            
            return UnreadCountResponse(unread_count=unread_count)
            
        except Exception as e:
            logger.error(f"获取未读数量失败: {e}")
            return UnreadCountResponse(unread_count=0)

    def _get_all_active_notifications(self) -> List[NotificationInDB]:
        """获取所有活跃的通知"""
        try:
            query_body = {
                "query": {
                    "bool": {
                        "must": [
                            {"term": {"is_active": True}}
                        ]
                    }
                },
                "sort": [{"created_at": {"order": "desc"}}],
                "size": 1000  # 限制最大数量，避免性能问题
            }
            
            result = self.es.search(
                index=self.notification_index,
                body=query_body
            )
            
            notifications = []
            for hit in result["hits"]["hits"]:
                notifications.append(NotificationInDB(**hit["_source"]))
            
            return notifications
            
        except Exception as e:
            logger.error(f"获取活跃通知失败: {e}")
            return []

    def _is_notification_visible_to_user(self, notification: NotificationInDB, user_id: str) -> bool:
        """判断通知是否对用户可见"""
        # 如果通知不活跃，不可见
        if not notification.is_active:
            return False
        
        # 如果通知已过期，不可见
        if notification.expires_at and datetime.fromisoformat(notification.expires_at) < datetime.now(timezone.utc):
            return False
        
        # 如果目标用户为空，表示所有用户可见
        if not notification.target_users:
            return True
        
        # 如果用户在目标用户列表中，可见
        return user_id in notification.target_users

    def _get_or_create_user_notification_status(self, user_id: str, notification_id: str) -> dict:
        """获取或创建用户通知状态记录"""
        try:
            # 尝试获取现有记录
            result = self.es.search(
                index=self.user_notification_index,
                body={
                    "query": {
                        "bool": {
                            "must": [
                                {"term": {"user_id": user_id}},
                                {"term": {"notification_id": notification_id}}
                            ]
                        }
                    }
                }
            )
            
            if result["hits"]["total"]["value"] > 0:
                # 记录存在，返回现有状态
                return result["hits"]["hits"][0]["_source"]
            else:
                # 记录不存在，创建新记录
                now = datetime.now(timezone.utc)
                user_notification_data = {
                    "user_id": user_id,
                    "notification_id": notification_id,
                    "is_read": False,
                    "read_at": None,
                    "created_at": now.isoformat()
                }
                
                self.es.index(
                    index=self.user_notification_index,
                    body=user_notification_data
                )
                
                return user_notification_data
                
        except Exception as e:
            logger.error(f"获取或创建用户通知状态失败: {e}")
            # 返回默认状态
            return {
                "user_id": user_id,
                "notification_id": notification_id,
                "is_read": False,
                "read_at": None,
                "created_at": datetime.now(timezone.utc).isoformat()
            }

    def sync_user_notifications(self, user_id: str):
        """为新用户同步所有可见的通知"""
        try:
            # 获取所有活跃通知
            all_notifications = self._get_all_active_notifications()
            
            synced_count = 0
            for notification in all_notifications:
                if self._is_notification_visible_to_user(notification, user_id):
                    # 创建用户通知状态记录
                    self._create_user_notification_record(user_id, notification.id)
                    synced_count += 1
            
            logger.info(f"为用户 {user_id} 同步了 {synced_count} 条通知")
            
        except Exception as e:
            logger.error(f"同步用户通知失败: {e}")

    def _create_user_notification_record(self, user_id: str, notification_id: str):
        """创建单个用户通知记录"""
        try:
            now = datetime.now(timezone.utc)
            user_notification_data = {
                "user_id": user_id,
                "notification_id": notification_id,
                "is_read": False,
                "read_at": None,
                "created_at": now.isoformat()
            }
            
            self.es.index(
                index=self.user_notification_index,
                body=user_notification_data
            )
            
        except Exception as e:
            logger.error(f"创建用户通知记录失败: {e}")
    
    def mark_as_read(self, user_id: str, notification_id: str) -> bool:
        """标记通知为已读"""
        try:
            now = datetime.now(timezone.utc)
            
            # 更新用户通知状态
            self.es.update_by_query(
                index=self.user_notification_index,
                body={
                    "query": {
                        "bool": {
                            "must": [
                                {"term": {"user_id": user_id}},
                                {"term": {"notification_id": notification_id}}
                            ]
                        }
                    },
                    "script": {
                        "source": "ctx._source.is_read = true; ctx._source.read_at = params.read_at",
                        "lang": "painless",
                        "params": {
                            "read_at": now.isoformat()
                        }
                    }
                }
            )
            
            logger.info(f"标记通知已读成功: 用户{user_id}, 通知{notification_id}")
            return True
            
        except Exception as e:
            logger.error(f"标记通知已读失败: {e}")
            return False
    
    def batch_delete_notifications(self, notification_ids: List[str]) -> bool:
        """批量删除通知"""
        try:
            for notification_id in notification_ids:
                self.delete_notification(notification_id)
            
            logger.info(f"批量删除通知成功: {len(notification_ids)}个")
            return True
            
        except Exception as e:
            logger.error(f"批量删除通知失败: {e}")
            return False
